// Unit Test for Alloc<> template class.

#include "allocTmpl.h"
#include "unitTest.h"

using namespace simple;

namespace simple_test{

    UTFUNC(null)
    {
        setDescription ("Null alloc");

        Alloc<int> data;
        VERIFY (data.size() == 0);
        VERIFY (data.data() == Alloc<int>::gNull().data());
        VERIFY (data.isNull());

        Alloc<int> data2 (2);
        VERIFY (!data2.isNull());
    }


    UTFUNC(simple)
    {
        setDescription ("Simple test of accessors");

        int i;
        Alloc<int> data (10);

        VERIFY (data.size() == 10);
        VERIFY (data.ref() == 1);

        const Alloc<int> data2 = data;
        for (i=0; i<data.size(); i++) {
            VERIFY (data[i] == data2[i]);
        }
    }

    UTFUNC(alignment)
    {
        setDescription ("Memory alignment");

        Alloc<int> data2 (10, 2);
        Alloc<int> data4 (10, 4);
        Alloc<int> data8 (10, 8);
        Alloc<int> data3 (10, 1024);

        VERIFY ((reinterpret_cast<int>((const int*)data2.data()) & 1) == 0);
        VERIFY ((reinterpret_cast<int>((const int*)data4.data()) & 3) == 0);
        VERIFY ((reinterpret_cast<int>((const int*)data8.data()) & 7) == 0);
        VERIFY ((reinterpret_cast<int>((const int*)data3.data()) & 1023) == 0);
    }

    UTFUNC(set1)
    {
        setDescription ("Set/get memory with []");

        int i;
        Alloc<int> data (10);

        for (i=0; i<data.size(); i++)
            data[i] = i;

        for (i=0; i<data.size(); i++) {
            VERIFY(data[i] == i);
        }

        const Alloc<int> data2 = data;
        for (i=0; i<data2.size(); i++) {
            VERIFY(data2[i] == i);
        }

    }

    UTFUNC(set2)
    {
        setDescription ("Set/get memory with *");

        int i;
        Alloc<int> data (10);

        int* p1 = data.data();
        for (i=0; i<data.size(); i++)
            *p1++ = i;

        p1 = data.data();
        for (i=0; i<data.size(); i++)
            VERIFY(*p1++ == i);

        const Alloc<int> data2 = data;
        const int* p2 = data2.data ();
        for (i=0; i<data2.size(); i++)
            VERIFY(*p2++ == i);
    }


    UTFUNC(assign)
    {
        setDescription ("assign");

        int i;
        Alloc<int> data (10);

        for (i=0; i<data.size(); i++)
            data[i] = i;

        // Verify that no pixels are copied
        Alloc<int> data2 = data;
        VERIFY(data2.data() == data.data());
        for (i=0; i<data.size(); i++) {
            VERIFY(data[i] == i);
            VERIFY(data2[i] == i);
        }
    }



    UTFUNC(duplicate)
    {
        setDescription ("Test duplicate() explicity");

        int i;
        Alloc<int> data (10, true);
        for (i=0; i<data.size(); i++)
            data[i] = i;
        VERIFY (data.ref() == 1);

        const int* p1 = data.data();
        data.duplicate ();
        VERIFY (p1 == data.data()); // nop if only 1 reference count

        // Create a second reference
        Alloc<int> data2 = data;
        VERIFY (data.ref() == 2);
        VERIFY (data.data() == data2.data());

        // Explicitly duplicate the data
        data2.duplicate ();
        VERIFY (data.ref() == 1);
        VERIFY (data2.ref() == 1);
        VERIFY (data.data() != data2.data());
        VERIFY (p1 == data.data());

        for (i=0; i<data.size(); i++) {
            VERIFY (data[i] == i);
            VERIFY (data2[i] == i);
        }
    }


    UTFUNC(largeAlloc)
    {
        setDescription ("1000 large allocations");

        int i;

        Alloc<char> image (1);
        for (i=0; i<1000; i++) {
            image = Alloc<char> (1024*1024);
            VERIFY (image.ref() == 1);
        }
    }


    UTFUNC(exception)
    {
        setDescription ("Exceptions");

        int i;
        Alloc<int> data (10);

        // This should generate 2 exceptions
        int caught = 0;
        int sum = 0;
        int sz = data.size();
        for (i=-1; i<sz + 1; i++) {
            try {
                sum += data[i];
            }
            catch (const std::range_error&) {
                caught++;
            }
        }


        VERIFY (caught == 2);
    }

}